<?php
namespace wechat;

use app\common\model\Car;
use curl\MyCurl;
use think\Config;
use think\Log;
use think\Request;

/**
 * 微信接口
 *
 * @author lipeng
 */
class Wechat
{

    protected $appID;
    protected $appSecret;
    protected $px;
    protected $wx;
    protected $error;
    protected $token;
    protected $EncodingAESKey;
    protected $text_tpl = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[%s]]></MsgType><Content><![CDATA[%s]]></Content><FuncFlag>0</FuncFlag></xml>";
    protected $img_tpl = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[%s]]></MsgType><Image><MediaId><![CDATA[%s]]></MediaId></Image></xml>";


    public function __construct()
    {
        $this->px = Config::get("database")["prefix"];
        $wx = \think\Db::table($this->px."wx")->where("id", 1)->find();
        if ($wx) {
            $this->wx = $wx;
            $this->appID = $wx["appId"];
            $this->appSecret = $wx["appSecret"];
            $this->token = $wx["token"];
            $this->EncodingAESKey = $wx['EncodingAESKey'];
        } else {
            throw new \Exception("微信账号不存在");
        }
    }

    //生成jsSDK配置
    public function jsSDKConfig($data = [])
    {
        $timestamp = time();
        $data["appId"] = isset($data["appId"]) ? $data["appId"] : $this->appID;
        $data["timestamp"] = isset($data["timestamp"]) ? $data["timestamp"] : time();
        $data["nonceStr"] = isset($data["nonceStr"]) ? $data["nonceStr"] : $this->nonceStr();
        if(!isset($data["url"]))
        {
            $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
            $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
            $data["url"] = $url;
        }

        $data["signature"] = $this->signature($data);
        $data["jsApiList"] = isset($data["jsApiList"]) ? $data["jsApiList"] : [];
        $config = [
            "debug" => isset($data["debug"]) ? $data["debug"] : false,
            "appId" => $data['appId'], // 必填，公众号的唯一标识
            "timestamp" => $timestamp, // 必填，生成签名的时间戳
            "nonceStr" => $data["nonceStr"], // 必填，生成签名的随机串
            "signature" => $data["signature"], // 必填，签名，见附录1
            "jsApiList" => $data["jsApiList"] // 必填，需要使用的JS接口列表，所有JS接口列表见附录2            
        ];
       /// Log::info($config);
       // Log::info($config);
        return $config;
    }

    //生成随机字符串
    public function nonceStr($lenght = 16)
    {
        $str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        $nonceStr = "";
        for ($i = 0; $i < $lenght; $i++) {
            $rand = rand(0, strlen($str) - 1);
            $nonceStr .= $str[$rand];
        }
        return $nonceStr;
    }

    //生成签名
    public function signature($data)
    {
        $jsapiTicket = $this->jsapiTicket();
        $noncestr = $data["nonceStr"];
        $timestamp = $data["timestamp"];
        $url = $data["url"];
        $signData = [
            "jsapi_ticket" => $jsapiTicket,
            "noncestr" => $noncestr,
            "timestamp" => $timestamp,
            "url" => $url,
        ];
        ksort($signData);

        $str = "jsapi_ticket={$jsapiTicket}&noncestr={$noncestr}&timestamp={$timestamp}&url={$url}";

        $str = sha1($str);

        return $str;
    }

    //获取accessToken
    public function accessToken()
    {
        if (empty($this->wx["access_token"]) || $this->wx["token_expires_in"] < time()) {
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appID}&secret={$this->appSecret}";
            $ret = file_get_contents($url);


            if ($ret) {
                $ret = json_decode($ret, true);
                if (isset($ret["access_token"]) && isset($ret["expires_in"])) {
                    $data = [
                        "access_token" => $ret["access_token"],
                        "token_expires_in" => time() + $ret["expires_in"] - 300,
                    ];
                    \think\Db::table($this->px."wx")->where("id", $this->wx['id'])->update($data);
                    $this->wx = \think\Db::table($this->px."wx")->where("id", $this->wx['id'])->find();
                } else {
                    throw new \Exception("accessToken获取失败");
                }
            } else {
                throw new \Exception("accessToken获取失败");
            }
        }
        return $this->wx["access_token"];
    }





    //获取jsapi_ticket
    public function jsapiTicket()
    {
        if (empty($this->wx["jspapi_ticket"]) || $this->wx["ticket_expires_in"] < time()) {
            $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={$this->accessToken()}&type=jsapi";
            $ret = file_get_contents($url);
            if ($ret) {
                $ret = json_decode($ret, true);
                if (isset($ret["errcode"]) && $ret["errcode"] == 0) {
                    $data = [
                        "jspapi_ticket" => $ret["ticket"],
                        "ticket_expires_in" => time() + $ret["expires_in"] - 300,
                    ];
                    \think\Db::table($this->px."wx")->where("id", $this->wx['id'])->update($data);
                    $this->wx = \think\Db::table($this->px."wx")->where("id", $this->wx['id'])->find();
                } else {
                    $errmsg = isset($ret['errmsg']) ? $ret['errmsg'] : "";
                    throw new \Exception("ticket获取失败" . $errmsg);
                }
            } else {
                throw new \Exception("ticket获取失败");
            }
        }
        return $this->wx["jspapi_ticket"];
    }


    private function checkSignature($params)
    {
        $tmpArr = array($this->token, $params["timestamp"], $params["nonce"]);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode( $tmpArr );
        $tmpStr = sha1( $tmpStr );

        $cm = new Car();
        $cm->table("__SYS__")->insert(["content"=>$tmpStr."==>".$params["signature"]]);

        //dump($tmpStr);
        //dump($params["signature"]);
        if( $tmpStr == $params["signature"] ){
            return true;
        }else{
            return false;
        }


    }

    //基本配置验证
    public function valid()
    {
        $params = Request::instance()->param();
        if ($this->checkSignature($params)) {
            die($params['echostr']);
        }
    }

    //检查消息签名
    public function decryptMsg($responeData)
    {
        $data = [
            $this->token,
            $responeData["timestamp"],
            $responeData["nonce"]
        ];
        sort($data, SORT_STRING);
        $str = implode($data);
        if (sha1($str) == $responeData["signature"]) {
            return true;
        } else {
            return false;
        }
    }

    //创建公众号之定义菜单
    public function createMenus($menu)
    {
        $menus = json_encode($menu, JSON_UNESCAPED_UNICODE);
        //$menus = urlencode($menus);
        $url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token={$this->accessToken()}";
        $ret = MyCurl::send($url, $menus, "post");

        //dump($this->accessToken());

        return $ret;
    }

    //获取公众号菜单
    public function getMenus()
    {
        $url = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token={$this->accessToken()}";
        $ret = file_get_contents($url);
        var_dump($url);
    }

    //普通接口获取用户信息
    //获取用户信息，可判断关注状态
    public function getUserInfo2($openid)
    {
        $url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={$this->accessToken()}&openid={$openid}&lang=zh_CN";
        $ret = file_get_contents($url);
        if ($ret) {
            return json_decode($ret, true);
        } else {
            return [];
        }
    }



    //获取openid
    public function getUserInfo_openid($code)
    {
        $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$this->appID.'&secret='.$this->appSecret.'&code='.$code.'&grant_type=authorization_code';

        $ret = file_get_contents($url);

        $ret = json_decode($ret, true);

        return $ret;

    }



    //授权后获取用户信息
    public function getUserInfo($code)
    {

        $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$this->appID.'&secret='.$this->appSecret.'&code='.$code.'&grant_type=authorization_code';

        $ret = file_get_contents($url);

        //dump($ret);

        if ($ret) {

            $ret = json_decode($ret, true);

            $access_token = $ret['access_token'];
            $openid = $ret['openid'];

            $url = "https://api.weixin.qq.com/sns/userinfo?access_token=".$access_token."&openid=".$openid."&lang=zh_CN";

            $ret = file_get_contents($url);
            if ($ret) {
                return json_decode($ret, true);
            } else {
                return [];
            }

        }
        else
        {
            return [];
        }

    }

    /**
     * 消息类型判断
     * @return array
     */
    public function responseMsg()
    {
        //因为很多都设置了register_globals禁止,不能用$GLOBALS["HTTP_RAW_POST_DATA"] 改用file_get_contents("php://input")即可
        $postStr = file_get_contents("php://input");
        if (!empty($postStr)){
            $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            $RX_TYPE = trim($postObj->MsgType);
            //用户发送的消息类型判断
            switch ($RX_TYPE)
            {
                case "text":    //文本消息
                    return array('type'=>'text','msg'=>'文本','obj'=>$postObj);
                    break;
                case "image":   //图片消息
                    return array('type'=>'image','msg'=>'图片','obj'=>$postObj);
                    break;

                case "voice":   //语音消息
                    return array('type'=>'voice','msg'=>'语音','obj'=>$postObj);
                    break;
                case "video":   //视频消息
                    return array('type'=>'video','msg'=>'视频','obj'=>$postObj);
                    break;
                case "location"://位置消息
                    return array('type'=>'location','msg'=>'位置','obj'=>$postObj);
                    break;
                case "link":    //链接消息
                    return array('type'=>'link','msg'=>'链接','obj'=>$postObj);
                    break;

                case "event":    //链接消息
                    return array('type'=>'event','msg'=>'事件','obj'=>$postObj);
                    break;

                default:
                    return array('type'=>'unknow msg type','msg'=>'未知','obj'=>$postObj);
                    break;
            }
        }else {
            echo "";
            exit;
        }
    }






    //curl发送模板消息
    public function sendTplMsg($toUser, $template_id, $data, $link = "")
    {
        $url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={$this->accessToken()}";
        $postData = [
            "touser" => $toUser,
            "template_id" => $template_id,
            "data" => $data
        ];
        if ($link) $postData['url'] = $link;
        $postData = json_encode($postData, JSON_UNESCAPED_UNICODE);
        $ret = MyCurl::send($url, $postData, "post");
        return $ret;
    }


    //curl发送模板消息
    public function qrcodeCreate($str)
    {
        $url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={$this->accessToken()}";
        $postData = [
            "action_name" => "QR_LIMIT_SCENE",
            "action_info" => [
                "scene"=>[
                    "scene_id"=>$str
                ]
            ]
        ];
        $postData = json_encode($postData, JSON_UNESCAPED_UNICODE);
        $ret = MyCurl::send($url, $postData, "post");
        return $ret;
    }



    //发送模板消息
    public function sendTplMsg_bak($toUser, $template_id, $data, $link = "")
    {
        $postData = [
            "touser" => $toUser,
            "template_id" => $template_id,
            "data" => $data
        ];
        if ($link) $postData['url'] = $link;
        $postData = json_encode($postData, JSON_UNESCAPED_UNICODE);
        $fp = fsockopen('api.weixin.qq.com', 80, $error, $errstr, 10);
        $http = "POST /cgi-bin/message/template/send?access_token={$this->accessToken()} HTTP/1.1\r\nHost: api.weixin.qq.com\r\nContent-type: application/x-www-form-urlencoded\r\nContent-Length: " . strlen($postData) . "\r\nConnection:close\r\n\r\n$postData\r\n\r\n";
        fwrite($fp, $http);
        $resp_str = "";
        while(!feof($fp)){
            $resp_str .= fgets($fp,512);//返回值放入$resp_str
        }
        fclose($fp);
        $rs = explode("\r\n\r\n",$resp_str);
        if(isset($rs[1])){
            $rs = $rs[1];
        }else{
            $rs = explode(PHP_EOL.PHP_EOL,$resp_str);
            $rs = isset($rs[1])?$rs[1]:"{}";
        }
        return $rs;
    }

    //网页授权链接
    public function urlAuth_openid($redirect_url, $state = 0)
    {
        $redirect_url = urlencode($redirect_url);
        $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appID}&redirect_uri={$redirect_url}&response_type=code&scope=snsapi_base&state={$state}#wechat_redirect";
        //$url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appID}&redirect_uri={$redirect_url}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
        return $url;
    }


    public function urlAuth($redirect_url, $state = 0)
    {
        $redirect_url = urlencode($redirect_url);
        //$url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appID}&redirect_uri={$redirect_url}&response_type=code&scope=snsapi_base&state={$state}#wechat_redirect";
        $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appID}&redirect_uri={$redirect_url}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
        //header('Location: '.$url);
        return $url;
    }




    //获取网页授权access_token
    public function getAuthInfo($code)
    {
        $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->appID}&secret={$this->appSecret}&code={$code}&grant_type=authorization_code";
        $ret = file_get_contents($url);
        return json_decode($ret, true);
    }

    //获取素材
    public function getMaterial($type, $offset = 0, $count = 10)
    {
        $url = "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token={$this->accessToken()}";
        $postData = [
            "type" => $type,
            "offset" => $offset,
            "count" => $count
        ];
        $postData = json_encode($postData, JSON_UNESCAPED_UNICODE);
        $ret = MyCurl::send($url, $postData, "post");
        $ret = json_decode($ret, true);
        return $ret;
    }

}
